<?php
/**
 * Soar Framework - Lightweight and simple to use PHP Framework
 *
 * Soar is free software and is distributed WITHOUT ANY WARRANTY
 *
 * @package Soar
 * @version 1.0 $Id: SoarDebugger.php 2 2012-04-06 21:50:33Z shay@shayanderson.com $
 * @copyright Copyright (c) 2012 ShayAnderson.com
 * @license http://www.gnu.org/licenses/gpl.html GPL License
 * @link http://www.shayanderson.com/projects/soar-php-framework.htm
 */

/**
 * Soar Framework Debugger
 *
 * @package Soar
 * @name SoarDebugger
 * @author Shay Anderson 04.12
 */
final class SoarDebugger
{
	/**
	 * Logging levels
	 */
	const LEVEL_OFF = 0;
	const LEVEL_ERROR = 1;
	const LEVEL_DEBUG = 2;
	const LEVEL_ALL = 3;

	/**
	 * Log file write flag
	 *
	 * @var bool
	 */
	private static $__is_written = false;

	/**
	 * Logging level
	 *
	 * @var int
	 */
	private static $__level = self::LEVEL_OFF;

	/**
	 * Log lines
	 *
	 * @var array
	 */
	private static $__log = array();

	/**
	 * Log file path
	 *
	 * @var string
	 */
	private static $__log_file;

	/**
	 * Dump log file flag
	 *
	 * @var bool
	 */
	public static $__log_file_dump = false;

	/**
	 * Max log line limit log file
	 *
	 * @var int
	 */
	public static $__log_max_lines = 300;

	/**
	 * Start mark
	 *
	 * @var float
	 */
	private static $__mark_start;

	/**
	 * Start time stamp
	 *
	 * @var string
	 */
	private static $__ts_start;

	/**
	 * Format log line
	 *
	 * @param mixed $line
	 * @return mixed
	 */
	private static function __formatLine($line = NULL)
	{
		return $line . PHP_EOL;
	}

	/**
	 * Initialize debugger params
	 *
	 * @param int $log_level
	 * @param string $log_file
	 * @param bool $log_file_dump
	 * @param int $log_max_lines
	 * @return void
	 */
	public static function init($log_level = self::LEVEL_OFF, $log_file = '', $log_file_dump = false, $log_max_lines = 300)
	{
		self::$__level = (int)$log_level;
		self::$__log_file = $log_file;
		self::$__log_file_dump = (bool)$log_file_dump;
		self::$__log_max_lines = (int)$log_max_lines;
	}

	/**
	 * Log message
	 *
	 * @param string $log_message
	 * @param int $level
	 * @return void
	 */
	public static function log($log_message, $level = self::LEVEL_ALL)
	{
		if(self::$__mark_start == NULL)
		{
			self::$__mark_start = microtime(true);
			self::$__ts_start = date('m/d/Y H:i:s') . ' - ' . self::$__mark_start;
			self::log(__CLASS__ . ': initialized', SoarDebugger::LEVEL_DEBUG);
			self::log('Directory Base: "' . SOAR_DIR_BASE . '"', SoarDebugger::LEVEL_DEBUG);
			self::log($log_message, $level);
			return;
		}
		if(!empty($log_message))
		{
			if($level <= self::$__level)
			{
				self::$__log[] = array(
					'mark' => microtime(true),
					'msg' => $log_message,
				);
			}
		}
	}

	/**
	 * Write to log file
	 *
	 * @return void
	 */
	public static function writeLog()
	{
		if(count(self::$__log) > 0)
		{
			$log = array();
			$log[] = '=======================================================';
			$log[] = self::$__ts_start;
			$log[] = '=======================================================';
			$last_mark = NULL;
			foreach(self::$__log as $v)
			{
				$log[] = '[+' . (number_format($v['mark'] - self::$__mark_start, 3)) . '] '
					. $v['msg'];
				$last_mark = $v['mark'];
			}
			if($last_mark !== NULL)
			{
				$log[] = 'Total: +' . (number_format($last_mark - self::$__mark_start, 3))
					. ' seconds';
			}
			$log[] = '';
			if(!self::$__is_written)
			{
				if(self::$__log_max_lines > 0)
				{
					$log = array_map(array(__CLASS__, '__formatLine'), $log);
					$is_file = is_file(self::$__log_file);
					if($is_file && !is_writable(self::$__log_file))
					{
						trigger_error('Failed to write log file "' . self::$__log_file . '", file is not writable',
							SoarErrorHandler::ERROR);
					}
					else if(!is_writable(substr(self::$__log_file, 0, strrpos(self::$__log_file, DIRECTORY_SEPARATOR))))
					{
						trigger_error('Failed to write log file "' . self::$__log_file
							. '", log file directory is not writable', SoarErrorHandler::ERROR);
					}
					$log_file = $is_file ? file(self::$__log_file) : array();
					$log_file = array_merge($log_file, $log);
					if(self::$__log_max_lines > 0 && count($log_file) > self::$__log_max_lines)
					{
						$log_file = array_slice($log_file, (count($log_file) - self::$__log_max_lines + 1));
					}
					$log_file = implode('', $log_file);
					file_put_contents(self::$__log_file, $log_file, LOCK_EX);
				}
				if(self::$__log_file_dump)
				{
					echo '<p>' . implode('<br />', $log) . '</p>';
				}
				self::$__is_written = true;
			}
		}
	}
}
?>